# 1、w 写模式，它是不能读的，如果用w模式打开一个已经存在的文件，会清空以前的文件内容，重新写
#    w+ 是读写内容，只要沾上w，肯定会清空原来的文件
# 2、r 读模式，只能读，不能写，而且文件必须存在
#    r+ 是读写模式，只要沾上r，文件必须存在
# 3、a 追加模式，也能写,在文件的末尾添加内容
# 4、rb+、wb+、ab+,这种是二进制模式打开或者读取，一些音乐文件

import linecache

# 循环读取每一行,并迭代返回

import enforce as enforce


# 强行运行时检查参数类型
@enforce.runtime_validation
def cyclegetline(file: str):
    """
    读取文件 且文件必须存在 使用yield返回每一行 直到末尾 可以用与for循环
    测试例子
    for line in cyclegetline("test.txt"):
        print(line)
    :param file:
    :return:
    """
    file = open(file, 'r+')
    for line in file:
        print(type(line))
        yield line  # type: str
    file.close()


# 用with的方式打开文件，不用担心使用完文件后忘记关闭，它会自动将文件关闭
def cyclegetlinewith(file: str):
    """
    对可迭代对象 f，进行迭代遍历：for line in f，会自动地使用缓冲IO（buffered IO）以及内存管理，
    而不必担心任何大文件的问题。
    """
    with open(file, 'r+') as file:
        for line in file:
            yield line


def write_file_r_add_model(file: str, content: str) -> None:
    """
    写文件 且文件必须存在 该模式会覆盖原来的内容
    但不是先清空再写 比如 原来有10个字符
    现在写入4个 那么前4个会被覆盖
    测试例子
    write_file_r_add_model("test2.txt","$$$$$$$$$")
    :param file:
    :return:
    """
    file = open(file, 'r+')
    file.write(content)
    file.close()


def write_file_w_model(file: str, content: str):
    """
    如果文件不存在 将创建
    如果文件存在 清空并重写
    :param file:
    :param content:
    :return:
    """
    with open(file, 'w') as file:
        file.write(content)


def read_file_w_add_model(file: str, content: str) -> str:
    """
    文件不存在  创建
    文件存在 直接调取 file.read()是无返回的 因为被清空
    这种模式存在的意义是先写再读
    如下
    :param file:
    :return:
    """
    with open(file, 'w+') as file:
        file.write(content)
        file.seek(0)
        result = file.read()
        return result


def write_file_a_model(file: str, content: str):
    """
    如果文件不存在 将创建
    如果文件存在 追加内容到后面
    :param file:
    :param content:
    :return:
    """
    with open(file, 'a') as file:
        file.write(content)


def read_file_a_add_model(file: str, content: str):
    """
    如果文件不存在 将创建
    如果文件存在 无法直接读取文件 但可以通过  file.seek(0)后读取
    :param file:
    :param content:
    :return:
    """
    with open(file, 'a+') as file:
        file.write(content)
        file.seek(0)   # 移动文件指针
        return file.read()  # content 类型是字符串

def write_file(filename, content):
    '''
     用来读取文件内容的
     :param filename: 文件名
     '''
    # with open(filename, 'a+') as fw:
    #     print(type(fw))
    #     fw.seek(0)  # 移动文件指针
    #     fw.truncate()  # 清空文件内容
    #     fw.write(str(content))
    fw = open(filename, 'a+')
    print(type(fw))
    fw.write(str(content))
    print(fw.seek(3,1))  # 移动文件指针
    fw.truncate()  # 清空文件内容
    fw.write(str(content))
    fw.close()




"""
.readline() 和 .readlines() 之间的差异是后者一次读取整个文件，象 .read() 一样。
.readlines() 自动将文件内容分析成一个行的列表，该列表可以由 Python 
的 for ... in ... 结构进行处理。另一方面，.readline() 每次只读取一行，
通常比 .readlines() 慢得多。仅当没有足够内存可以一次读取整个文件时，
才应该使用 .readline()。
"""


def get_line_date(file, line_num):
    """
    获取指定行数据
    :param file: 
    :param line_num: 
    :return: 
    """
    with open(file, 'r') as fr:
        # 可以接受一个数值参数
        line = fr.readlines()
        line_need = line[line_num - 1]
        return line_need


def get_line_date2(file, line_num):
    """
    获取指定行数据
    :param file: 
    :param line_num: 
    :return: 
    """
    with open(file, 'r') as fr:
        lines = fr.readline()
        for line in lines:
            print(line)


def get_file_date_for_buffer(f):
    """
    指定每次读取大小读取文件，暂时没有使用过
    :param f: 
    :return: 
    """
    while True:
        block = f.read(1024)
        if not block:
            break


def get_linecache_line(filename, linenum):
    """
    读取某行的文件
    :param filename: 
    :param linenum: 
    :return: 
    """
    count = linecache.getline(filename, linenum)


def get_linecache_lines(filename, linenum):
    """
    读取全部文件
    返回一个列表
    :param filename: 
    :param linenum: 
    :return: 
    """
    count = linecache.getline(filename, linenum)
